package com.dopplr.api
{
    /** creates Travellers, Trips and Cities from Dopplr's XML API, 
     *  and keeps track of all the ones we know about so far. */
    public class Model
    {
        /** all the cities we know about so far */
        public var cities:Array = [];        
        /** all cities we know about indexed by geonames id */
        public var citiesById:Object = {};
        
        /** all the users we know about so far */
        public var travellers:Array = [];
        /** all users we know about indexed by nickname */
        public var travellersByNick:Object = {};
        
        /** all the trips we know about so far */
        public var trips:Array = [];
        /** all trips we know about indexed by id */
        public var tripsById:Object = {};
        
        /** creates a new traveller if we haven't seen a user with this nick before, 
         *  otherwise returns travellersByNick[user.nick.text()]
         *  and adds home city, current city and current_trip  (if provided) */
        public function getTravellerfromXML(traveller:XML):Traveller
        {
            var t:Traveller = travellersByNick[traveller.nick.text()];
            if (!t) {
                t = new Traveller();
                t.status = traveller.status.text();
                t.name = traveller.name.text();
                t.sha1email = traveller.sha1email.text();
                t.iconId = traveller.icon_id.text();
                t.nick = traveller.nick.text();
                t.url = traveller.url.text();
                t.travelToday = traveller.travel_today.text() == "true";
                travellersByNick[t.nick] = t;
            }
            if (!t.homeCity && traveller.home_city[0]) {
                t.homeCity = getCityFromXML(traveller.home_city[0]);
            }
            if (!t.currentCity && traveller.current_city[0]) {
                t.currentCity = getCityFromXML(traveller.current_city[0]);                    
            }
            if (!t.currentTrip && traveller.current_trip[0]) {
                t.currentTrip = getTripFromXML(traveller.current_trip[0]);
            }
            return t;
        }

        /** creates a new city if we haven't seen a city with this geonames ID before, 
         *  otherwise returns citiesById[city.geoname_id.text()] */   
        public function getCityFromXML(city:XML):City
        {
            var c:City = citiesById[city.geoname_id.text()];
            if (!c) {
                c = new City();
                c.countryCode = city.country_code.text();
                c.name = city.name.text();
                c.latitude = parseFloat(city.latitude.text());
                c.url = city.url.text();
                c.longitude = parseFloat(city.longitude.text());
                c.geonameId = city.geoname_id.text();
                c.rgb = parseInt(city.rgb, 16);
                citiesById[c.geonameId] = c;
                cities.push(c);
            }
            return c;
        }        
        
        /** creates a new trip if we haven't seen a city with this ID before, 
         *  otherwise returns tripsById[trip.id.text()] */   
        public function getTripFromXML(trip:XML):Trip
        {
            var t:Trip = tripsById[trip.id.text()];
            if (!t) {
                t = new Trip();
                t.city = getCityFromXML(trip.city[0]);
                t.departure = getCityFromXML(trip.departure[0]);
                t.id = parseInt(trip.id.text());
                t.start = parseTripDate(trip.start.text());
                t.finish = parseTripDate(trip.finish.text());
                for each (var note:XML in trip.note) {
                    t.notes.push(getNoteFromXML(note));
                }
                tripsById[t.id] = t;
                trips.push(t);
                t.city.trips.push(t)
            }
            return t;
        }
        
        /** we don't keep lists of these around because they're always attached to a trip, 
         *  but they're there if you want them */
        public function getNoteFromXML(note:XML):Note
        {
            var n:Note = new Note();
            n.updatedAt = parseNoteDate(note.updated_at.text());
            n.body = note.body.text();
            n.traveller = travellersByNick[note.traveller_nick.text()];
            n.createdAt = parseNoteDate(note.created_at.text());
            return n;
        }

        /** transforms a yyyy-mm-ddThh:mm:ss+hh:mm string into a Date, assuming these are always in UTC for now */
        public static function parseNoteDate(st:String):Date
        {
            // 2007-02-16T18:11:05+00:00
            // yyyy-mm-ddThh:mm:ss+hh:mm
            // 0000000000111111111122222
            // 0123456789012345678901234
            var yr:String = st.substr(0,4);
            var mo:String = st.substr(5,2);
            var da:String = st.substr(8,2);
            var ho:String = st.substr(11,2);
            var mi:String = st.substr(14,2);
            var se:String = st.substr(17,2);
            var y:int = parseInt(yr);
            var M:int = parseInt(mo) - 1; // 0-11!? why oh why?
            var d:int = parseInt(da);
            var h:int = parseInt(ho);
            var m:int = parseInt(mi);
            var s:int = parseInt(se);
            return new Date(Date.UTC(y,M,d,h,m,s));
        }
        
        /** transforms a "yyyy-mm-dd" String into a Date */
        public static function parseTripDate(s:String):Date
        {
            var yr:String = s.substr(0,4);
            var mo:String = s.substr(5,2);
            var da:String = s.substr(8,2);
            var y:int = parseInt(yr);
            var m:int = parseInt(mo) - 1; // 0-11!? why oh why?
            var d:int = parseInt(da);
            return new Date(Date.UTC(y,m,d));
        }

        
    }
}